package com.wei.czz.framework.annex.manager;

import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.dto.annex.*;
import com.wei.czz.common.dto.common.ChildrenNameValue;
import com.wei.czz.common.dto.common.NameValue;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.common.multiDIct.MultiDictEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.annex.AnnexClassifyEnum;
import com.wei.czz.common.enums.annex.AnnexConditionEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.UserPo;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.common.vo.annex.*;
import com.wei.czz.framework.annex.entity.AnnexConfigEntity;
import com.wei.czz.framework.annex.entity.AnnexGroupEntity;
import com.wei.czz.framework.annex.entity.AnnexPreEntity;
import com.wei.czz.framework.annex.helper.AnnexHelper;
import com.wei.czz.framework.annex.service.AnnexConfigService;
import com.wei.czz.framework.annex.service.AnnexGroupService;
import com.wei.czz.framework.annex.service.AnnexPreService;
import com.wei.czz.framework.annex.service.BusinessAnnexService;
import com.wei.czz.framework.common.service.SnowflakeService;
import com.wei.czz.framework.common.service.MultiDictService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2024-01-18 16:22:46
 * className: AnnexManager
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class AnnexManager {

    private static final Logger log = LoggerFactory.getLogger(AnnexManager.class);

    private final AnnexConfigService annexConfigService;

    private final AnnexGroupService annexGroupService;

    private final AnnexPreService annexPreService;

    private final BusinessAnnexService businessAnnexService;

    private final AnnexHelper annexHelper;

    private final MultiDictService multiDictService;

    private final SnowflakeService snowflakeService;

    private final RedissonClient redissonClient;

    @Transactional
    public void saveAnnex(AnnexVo annexVo) {

        /*
            保存附件动态配置前置
         */
        Long preId = annexPreService.saveAnnex(annexVo.getAnnexPreVo());

        /*
            保存附件动态配置分组
         */
        annexGroupService.saveAnnexGroup(preId, annexVo.getGroupList());

        /*
            保存附件动态配置字段
         */
        annexConfigService.saveAnnexConfig(preId, annexVo.getConfigList());

    }

    @Transactional
    public void copyAnnex(Long id) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        /*
            复制附件动态配置前置
         */
        Long preId = annexPreService.copyAnnexPre(id);

        /*
            获取附件动态配置分组
         */
        List<AnnexGroupEntity> annexGroupList = annexGroupService.getAnnexGroupList(id);
        log.info("需要复制的附件动态配置分组数量={}", annexGroupList.size());
        Iterator<AnnexGroupEntity> annexGroupIterator = annexGroupList.iterator();
        List<AnnexGroupEntity> saveAnnexGroupList = new ArrayList<>(annexGroupList.size());

        /*
            获取附件动态配置
         */
        List<AnnexConfigEntity> annexConfigList = annexConfigService.getAnnexConfigList(id, null);
        log.info("需要复制的附件动态配置数量={}", annexConfigList.size());

        /*
            批量获取新主键
         */
        List<Long> idList = snowflakeService.get(annexGroupList.size());
        Iterator<Long> idIterator = idList.iterator();

        // 分组主键映射
        Map<Long, Long> groupIdMap = new HashMap<>();

        while (annexGroupIterator.hasNext()) {
            AnnexGroupEntity annexGroup = annexGroupIterator.next();

            if (!idIterator.hasNext()) {
                log.error("主键生成个数不对。idList.size={}", idList.size());
                throw new CzzException();
            }
            Long groupId = idIterator.next();

            // 主键记录
            groupIdMap.put(annexGroup.getId(), groupId);

            annexGroup.setId(groupId)
                    .setPreId(preId)
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());

            if (CommonEnum.ZERO.getLongValue().equals(annexGroup.getParentId())) {
                saveAnnexGroupList.add(annexGroup);
                // 删除
                annexGroupIterator.remove();
            } else {
                // 获取新父级主键
                Long parentId = groupIdMap.get(annexGroup.getParentId());
                if (Objects.nonNull(parentId)) {
                    annexGroup.setParentId(parentId);
                    saveAnnexGroupList.add(annexGroup);
                    // 删除
                    annexGroupIterator.remove();
                }
            }
        }
        annexGroupIterator = annexGroupList.iterator();
        while (annexGroupIterator.hasNext()) {
            AnnexGroupEntity annexGroup = annexGroupIterator.next();

            // 获取新父级主键
            Long parentId = groupIdMap.get(annexGroup.getParentId());
            if (Objects.isNull(parentId)) {
                log.error("动态配置分组父级主键不存在。old.parentId={}", annexGroup.getParentId());
                throw new CzzException();
            }
            annexGroup.setParentId(parentId);

            saveAnnexGroupList.add(annexGroup);
            // 删除
            annexGroupIterator.remove();
        }
        log.info("附件动态配置分组复制数据构造完成");

        for (AnnexConfigEntity annexConfig : annexConfigList) {
            // 获取新分组主键
            Long groupId = groupIdMap.get(annexConfig.getGroupId());
            if (Objects.isNull(groupId)) {
                // 发生问题，根据groupId去分组表确认分组是否存在
                log.error("附件配置关联的新分组主键不存在。old.groupId={}", annexConfig.getGroupId());
            }

            annexConfig.setPreId(preId)
                    .setGroupId(groupId)
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
        }
        log.info("附件动态配置复制数据设置完成");

        /*
            批量保存附件动态配置分组
         */
        annexGroupService.batchSaveAnnexGroup(saveAnnexGroupList);

        /*
            批量保存附件动态配置
         */
        if (!annexConfigList.isEmpty()) {
            annexConfigService.batchSaveAnnexConfig(annexConfigList);
        }
    }


    public PageDto<AnnexPreDto> getAnnexPageList(AnnexFormVo annexFormVo) {

        /*
            分页获取附件动态配置前置
         */
        PageDto<AnnexPreEntity> pageDto = annexPreService.getAnnexPrePageList(annexFormVo);

        List<AnnexPreEntity> annexPreList = pageDto.getList();
        if (annexPreList.isEmpty()) {
            log.info("分页查询附件动态配置前置结果为空");
            return pageDto.rebuild();
        }

        List<AnnexPreDto> annexPreDtoList = annexPreList.stream()
                .map(AnnexPreDto::map)
                .collect(Collectors.toList());
        // 封装返回
        return pageDto.rebuild(annexPreDtoList);
    }

    public AnnexDto getAnnex(Long id) {

        /*
            获取附件动态配置前置
         */
        AnnexPreEntity annexPre = annexPreService.getAnnexPre(id);

        /*
            获取附件动态配置分组
         */
        List<AnnexGroupEntity> annexGroupList = annexGroupService.getAnnexGroupList(id);

        /*
            获取附件动态配置字段
         */
        List<AnnexConfigEntity> annexConfigList = Collections.emptyList();
        if (!annexGroupList.isEmpty()) {
            annexConfigList = annexConfigService.getAnnexConfigList(id, null);
        }

        List<AnnexGroupDto> annexGroupDtoList = new ArrayList<>();
        if (!annexGroupList.isEmpty()) {
            Map<String, AnnexGroupDto> annexGroupMap = new HashMap<>();
            List<AnnexGroupDto> lastOptList = new ArrayList<>();

            for (AnnexGroupEntity annexGroup : annexGroupList) {
                AnnexGroupDto annexGroupDto = AnnexGroupDto.map(annexGroup);

                annexGroupMap.put(annexGroupDto.getId(), annexGroupDto);

                AnnexGroupDto parentAnnexGroupDto = annexGroupMap.get(annexGroupDto.getParentId());
                if (Objects.isNull(parentAnnexGroupDto)) {
                    if (CommonEnum.ZERO.getStringValue().equals(annexGroupDto.getParentId())) {
                        annexGroupDtoList.add(annexGroupDto);
                    } else {
                        lastOptList.add(annexGroupDto);
                    }
                    continue;
                }
                TreeSet<AnnexGroupDto> children = parentAnnexGroupDto.getChildren();
                if (Objects.isNull(children)) {
                    children = new TreeSet<>();
                    parentAnnexGroupDto.setChildren(children);
                }
                children.add(annexGroupDto);
            }
            for (AnnexGroupDto annexGroupDto : lastOptList) {
                AnnexGroupDto parentAnnexGroupDto = annexGroupMap.get(annexGroupDto.getParentId());
                if (Objects.isNull(parentAnnexGroupDto)) {
                    log.info("父级附件动态配置分组不存在。{}", annexGroupDto);
                    continue;
                }
                TreeSet<AnnexGroupDto> children = parentAnnexGroupDto.getChildren();
                if (Objects.isNull(children)) {
                    children = new TreeSet<>();
                    parentAnnexGroupDto.setChildren(children);
                }
                children.add(annexGroupDto);
            }
        }
        annexGroupDtoList.sort(Comparator.comparing(AnnexGroupDto::getSort));

        List<AnnexConfigDto> annexConfigDtoList = new ArrayList<>();
        if (!annexConfigList.isEmpty()) {
            annexConfigDtoList = annexConfigList.stream()
                    .map(AnnexConfigDto::map)
                    .collect(Collectors.toList());
        }

        AnnexDto annexDto = new AnnexDto();
        annexDto.setAnnexPreDto(AnnexPreDto.map(annexPre))
                .setAnnexGroupList(annexGroupDtoList)
                .setAnnexConfigList(annexConfigDtoList);
        return annexDto;
    }

    public AnnexIndexEnumDto getAnnexIndexEnum() {

        AnnexIndexEnumDto annexIndexEnumDto = new AnnexIndexEnumDto();
        /*
            状态[0-启用 1-编辑 2-停用]
         */
        List<NameValue<Integer>> statusEnumList = new ArrayList<>();
        statusEnumList.add(new NameValue<>("启用", CommonEnum.ZERO.getValue()));
        statusEnumList.add(new NameValue<>("编辑", CommonEnum.ONE.getValue()));
        statusEnumList.add(new NameValue<>("停用", CommonEnum.TWO.getValue()));

        annexIndexEnumDto.setClassifyEnumList(AnnexClassifyEnum.getList())
                .setStatusEnumList(statusEnumList);
        return annexIndexEnumDto;
    }

    public AnnexAddEnumDto getAnnexAddEnum() {

        List<ChildrenNameValue<Integer>> storeClassList = multiDictService.getDictTree(
                MultiDictEnum.STORE_CLASS.getValue(), Integer::parseInt
        );
        List<NameValue<Integer>> mainClassList = new ArrayList<>(storeClassList.size());
        List<NameValue<Integer>> subClassList = new ArrayList<>(storeClassList.size());
        for (ChildrenNameValue<Integer> childrenNameValue : storeClassList) {
            mainClassList.add(new NameValue<>(childrenNameValue.getName(), childrenNameValue.getValue()));

            TreeSet<ChildrenNameValue<Integer>> children = childrenNameValue.getChildren();
            if (!CollectionUtils.isEmpty(children)) {
                for (ChildrenNameValue<Integer> nameValue : children) {
                    subClassList.add(new NameValue<>(nameValue.getName(), nameValue.getValue()));
                }
            }
        }

        AnnexAddEnumDto annexAddEnumDto = new AnnexAddEnumDto();

        annexAddEnumDto.setId(snowflakeService.find())
                .setClassifyEnumList(AnnexClassifyEnum.getList())
                .setConditionEnumList(AnnexConditionEnum.getList())
                .setMainClassList(mainClassList)
                .setSubClassList(subClassList);

        return annexAddEnumDto;
    }

    @Transactional
    public void updateAnnex(AnnexVo annexVo) {
        AnnexPreVo annexPreVo = annexVo.getAnnexPreVo();
        List<AnnexGroupVo> groupList = annexVo.getGroupList();
        List<AnnexConfigVo> fieldList = annexVo.getConfigList();

        String lockKey = RedisConstant.LOCK + EntityConstant.ANNEX + annexPreVo.getId();
        RLock lock = redissonClient.getLock(lockKey);
        // 尝试加锁
        boolean bool = lock.tryLock();
        log.info("修改附件动态配置，尝试加锁完成。lockKey={} bool={}", lockKey, bool);
        if (!bool) {
            throw new CzzException("附件配置正在修改中，请稍后重试");
        }
        try {
            /*
                修改附件动态配置前置
             */
            Long preId = annexPreService.saveAnnex(annexPreVo);

            /*
                修改附件动态配置分组
             */
            annexGroupService.saveAnnexGroup(preId, groupList);

            /*
                修改附件动态配置字段
             */
            annexConfigService.saveAnnexConfig(preId, fieldList);

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                // 解锁
                lock.unlock();
            }
        }
    }

    public void useAnnex(Long id) {

        String lockKey = RedisConstant.LOCK + EntityConstant.ANNEX + id;
        RLock lock = redissonClient.getLock(lockKey);
        boolean bool = lock.tryLock();
        log.info("修改附件动态配置状态，尝试加锁完成。lockKey={} bool={}", lockKey, bool);
        if (!bool) {
            throw new CzzException("启用附件配置正在操作中，无需重复操作");
        }
        try {

            /*
                获取附件配置
             */
            List<AnnexConfigEntity> annexConfigList = annexConfigService.getAnnexConfigList(id, null);
            if (annexConfigList.isEmpty()) {
                log.info("附件配置为空，不能启用。id={}", id);
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "附件配置为空，不能启用，操作失败");
            }

            /*
                启用附件动态配置前置状态
             */
            annexPreService.useAnnexPre(id);

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public void deleteAnnex(List<Long> idList) {
        /*
            删除附件动态配置前置
         */
        annexPreService.deleteAnnexPre(idList);
    }
}
